#region imported Namespaces
using System;
using System.Data;
using System.Data.SqlClient;
using System.Text;

using BO = PHSRAG.Insight21.BusinessObjects;
using Utility = PHSRAG.Utility;
using Utils = PHSRAG.Insight21.InsightUtilities;
using ICachePolicy = PHSRAG.Insight21.Policy.ICachePolicy;
using PHSRAG.Insight21.SearchContext;
#endregion

namespace PHSRAG.Insight21.Purchasing
{
	/// <summary>
	/// Business class for reconcile matched orders. 
	/// It supports loading of matched user order which the user has access to.
	/// It also has methods to support Sorting and filtering of user orders.
	/// </summary>
	public class ReconcileMatchedOrders: BO.BusinessObject
	{
		#region Constants (Private)
		private const string	ReconcileMatchedKey		= "ReconcileMatched_d42f1c8e-4258-42a7-84ad-15afb425976a";
		private const string	DefaultSortColumn		= "Amount";
		private const string	ReconcileMatchedSPName	= "GetReconcileMatched";
		private const string	InsightTableName		= "Insight";
		private const string	PSTableName				= "PS";
		private const string	OrderNumberColumnName	= "OrderNumber";
		private const string	OrderIDColumnName		= "OrderID";
		private const string	FundNumberColumnName	= "FundNumber";
		private const int		FirstRowIndex			= 0;
		
		#endregion

		#region Enumerations (Private)

		/// <summary>
		/// Enumerates the data tables returned by SP GetReconcileMatched
		/// </summary>
		private enum DataTableIndex
		{
			PeopleSoft,
			Insight,			
			Count
		}

		#endregion
	
		#region Instance Variables (Private)
		private bool			sortAscending	= true;
		// Keep this in sync with what the stored proc orders by.
		private string			sortColumn		= DefaultSortColumn;		
		#endregion

		#region Public Properties
		/// <summary>
		/// Get the key to be used in all caching operations for this instance of the object.
		/// </summary>
		public static string CacheKey	{ get { return ReconcileMatchedKey; } }
		/// <summary>
		/// Get the sort sequence.
		/// </summary>
		public bool SortAscending
		{
			get { return sortAscending; }
		}

		/// <summary>
		/// Get the name of the sort column.
		/// </summary>
		public string SortColumn
		{
			get { return sortColumn; }
		}
		#endregion
		
		#region Constructor

		/// <summary>
		/// Initializes the base class with the specified cache policy.
		/// </summary>
		/// <param name="cachePolicy">prevalent cache policy</param>
		public ReconcileMatchedOrders(ICachePolicy cachePolicy) : base(cachePolicy){}

		#endregion

		#region Public Methods
		
		/// <summary>
		/// Sorts and filters the reconcile matched user orders.
		/// Sort criteria is applied on the dataView containing the insight records.
		/// The sorted dataView is then looped through and matching records from the table containing
		/// the peoplesoft table is picked and imported in a new table. The default view of the new
		/// table containing both the insight and peoplesoft orders is returned to the calling method.
		/// </summary>
		/// <returns>DataView having sorted and filtered data.</returns>
		public DataView Sort()
		{
			DataView dataView = new DataView(DataContainer.Tables[InsightTableName]);

			dataView.Sort = string.Format("{0} {1}", sortColumn, sortAscending ? Constants.SortOrderAscending 
					: Constants.SortOrderDescending);

			DataTable matchedOrders = DataContainer.Tables[InsightTableName].Clone();

			foreach(DataRowView insightRowView in dataView)
			{
				DataRow[] peopleSoftRows = DataContainer.Tables[PSTableName].Select
					(string.Format(@"{0} = '{1}' AND {2} = {3} AND {4} = '{5}'", OrderNumberColumnName, 
					insightRowView[OrderNumberColumnName], OrderIDColumnName, 
					insightRowView[OrderIDColumnName], FundNumberColumnName, insightRowView[FundNumberColumnName]));
				
				if(peopleSoftRows.Length > 0)
				{
					matchedOrders.ImportRow(insightRowView.Row);
					matchedOrders.ImportRow(peopleSoftRows[FirstRowIndex]);
				}
			}
			return matchedOrders.DefaultView;
		}

		/// <summary>
		/// Uses the column name passed to set the sort order and sort column
		/// </summary>
		/// <param name="columnName">Column to sort by</param>
		public void ProcessSortCriteria(string columnName)
		{
			sortAscending = (sortColumn == columnName) ? !sortAscending : sortAscending;
			sortColumn = columnName;
		}

		#endregion

		#region Business Object Methods
		/// <summary>
		/// Initializes and loads the datacontainer with reconcile matched user orders.
		/// The method expects SearchCriteria object in the params object array.
		/// </summary>
		/// <param name="connectionString">connection string pointing to the database to get data from.</param>
		/// <param name="args">arguments to load the matched user order records.</param>
		public override void Load(string connectionString, params object[] args)
		{
			if (args[0] == null)
				throw new Exception("Reconcile matched load requires search criteria containing at least a domain user ID.");
			
			SearchCriteria searchCriteria = (SearchCriteria)args[0];

			try
			{				
				string daysTransactionsWithin = searchCriteria[Utils.Constants.PurchasingSearchKey.DaysTransactionsWithinKey];

				DataContainer = Utility.DataAccess.GetDataSet(connectionString, ReconcileMatchedSPName,
					Utility.DataAccess.BuildSqlParameterArray(
					"@domainUserID", SqlDbType.Int, searchCriteria[Utils.Constants.DomainUserIDKey],
					"@orderTypeID", SqlDbType.Int, searchCriteria[Utils.Constants.PurchasingSearchKey.UserOrderTypeViewKey],
					"@transactionStartDate", SqlDbType.DateTime,
					daysTransactionsWithin == null ? searchCriteria[Utils.Constants.PurchasingSearchKey.TransactionDateFromKey] : DateTime.Now.Date.AddDays(-Convert.ToDouble(daysTransactionsWithin)).ToShortDateString(),
					"@transactionEndDate", SqlDbType.DateTime,
					daysTransactionsWithin == null ? searchCriteria[Utils.Constants.PurchasingSearchKey.TransactionDateToKey] : DateTime.Now.ToShortDateString(),
					"@orderNumber", SqlDbType.VarChar, searchCriteria[Utils.Constants.PurchasingSearchKey.PONumberKey],
					"@piID", SqlDbType.Int, searchCriteria[Utils.Constants.PIIDKey],
					"@chiefCodeList", SqlDbType.VarChar, searchCriteria.COSIds,
					"@fundNumber", SqlDbType.VarChar, searchCriteria[Utils.Constants.FundIDKey],
					"@amount", SqlDbType.Money, searchCriteria[Utils.Constants.PurchasingSearchKey.TotalOrderAmountKey],
					"@requestorName", SqlDbType.VarChar, searchCriteria[Utils.Constants.PurchasingSearchKey.RequestorNameKey],
					"@vendorName", SqlDbType.VarChar, searchCriteria[Utils.Constants.PurchasingSearchKey.VendorNameKey],
					"@invoiceNumber", SqlDbType.VarChar, searchCriteria[Utils.Constants.PurchasingSearchKey.InvoiceNumberKey],
					"@invoiceDate", SqlDbType.DateTime, searchCriteria[Utils.Constants.PurchasingSearchKey.InvoiceDateKey]));

				if(!DataContainer.Tables.Count.Equals((int)DataTableIndex.Count))
					throw new Exception(string.Format("Failed to load data for matched orders. Expected {0} tables but {1} tables were returned.",
						(int)DataTableIndex.Count, DataContainer.Tables.Count));
				else
				{
					DataContainer.Tables[(int)DataTableIndex.PeopleSoft].TableName = PSTableName;
					DataContainer.Tables[(int)DataTableIndex.Insight].TableName = InsightTableName;
				}
			}
			catch(Exception ex)
			{
				throw(new Exception("Error in loading Reconcile Matched Orders.", ex));
			}			
		}

		/// <summary>
		/// Caches the ReconcileUnMatchedOrders object to cache using the prevalent cache policy
		/// </summary>
		public override void Cache()
		{
			CachePolicy.Cache(CacheKey,this);
		}

		/// <summary>
		///  Remove the current instance from the cache using the prevalent cache policy.
		/// </summary>
		public override void UnCache()
		{
			CachePolicy.UnCache(CacheKey);
		}

		#endregion		
	}
}
